#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import sys
import shutil
import subprocess
import argparse
from pathlib import Path


class DjangoProjectOptimizer:
    """Django项目结构优化工具"""

    def __init__(self, project_name, project_path=None):
        """
        初始化项目优化器
        
        Args:
            project_name: 项目名称
            project_path: 项目路径，默认为当前目录
        """
        self.project_name = project_name
        self.project_path = project_path or os.getcwd()
        self.base_dir = self.project_path
        self.apps_dir = os.path.join(self.base_dir, 'apps')
        
        # 基础应用列表 - 可以根据需要添加更多
        self.base_apps = ['accounts', 'common']
        
        # 创建的目录列表
        self.directories = ['media', 'static', 'templates']

    def run(self):
        """执行项目优化流程"""
        print(f"开始优化Django项目: {self.project_name}")
        
        # 1. 检查项目是否存在
        if not self.check_project_exists():
            print(f"错误: 项目 {self.project_name} 不存在于路径 {self.base_dir}")
            sys.exit(1)
        
        # 2. 创建基础目录
        self.create_directories()
        
        # 3. 创建apps目录和应用
        self.create_apps()
        
        # 4. 更新settings.py
        self.update_settings()
        
        # 5. 更新主urls.py
        self.update_urls()
        

        
        print(f"\n项目 {self.project_name} 已成功优化！")
        print("\n可以通过以下命令启动项目:")
        print("python manage.py migrate")
        print("python manage.py createsuperuser")
        print("python manage.py runserver")

    def check_project_exists(self):
        """检查项目是否存在"""
        # 检查manage.py文件
        if not os.path.exists(os.path.join(self.base_dir, 'manage.py')):
            return False
        
        # 检查项目配置目录
        if not os.path.exists(os.path.join(self.base_dir, self.project_name)):
            return False
            
        # 检查settings.py文件
        if not os.path.exists(os.path.join(self.base_dir, self.project_name, 'settings.py')):
            return False
            
        return True

    def create_directories(self):
        """创建基础目录结构"""
        print("正在创建基础目录...")
        
        for directory in self.directories:
            dir_path = os.path.join(self.base_dir, directory)
            os.makedirs(dir_path, exist_ok=True)
            print(f"已创建/确认目录: {directory}")
        
        # 在目录中创建一个空的.gitkeep文件以便Git可以跟踪该目录
        for directory in self.directories:
            gitkeep_path = os.path.join(self.base_dir, directory, '.gitkeep')
            if not os.path.exists(gitkeep_path):
                with open(gitkeep_path, 'w') as f:
                    pass

    def create_apps(self):
        """创建apps目录和基础应用"""
        print("正在创建apps目录和应用...")
        
        # 创建apps目录
        os.makedirs(self.apps_dir, exist_ok=True)
        
        # 创建apps/__init__.py使其成为Python包
        with open(os.path.join(self.apps_dir, '__init__.py'), 'w', encoding='utf-8') as f:
            pass
        
        # 为每个基础应用创建目录结构
        for app_name in self.base_apps:
            self._create_app(app_name)
    
    def _create_app(self, app_name):
        """创建单个应用"""
        print(f"正在创建应用: {app_name}")
        
        app_dir = os.path.join(self.apps_dir, app_name)
        
        # 如果应用目录已存在，询问是否覆盖
        if os.path.exists(app_dir):
            print(f"警告: 应用 {app_name} 已存在!")
            choice = input(f"是否覆盖应用 {app_name}? [y/N]: ").lower()
            if choice != 'y':
                print(f"跳过创建应用 {app_name}")
                return
            else:
                print(f"重新创建应用 {app_name}")
        
        os.makedirs(app_dir, exist_ok=True)
        
        # 创建基本文件
        files = {
            '__init__.py': '',
            'admin.py': 'from django.contrib import admin\n\n# Register your models here.\n',
            'apps.py': f'''from django.apps import AppConfig


class {app_name.capitalize()}Config(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'apps.{app_name}'
''',
            'models.py': 'from django.db import models\n\n# Create your models here.\n',
            'views.py': 'from rest_framework.views import APIView\nfrom apps.common.utils.response import Response\n\n# Create your views here.\n',
            'urls.py': '''from django.urls import path

urlpatterns = []
''',
            'tests.py': 'from django.test import TestCase\n\n# Create your tests here.\n',
        }
        
        # 写入文件
        for filename, content in files.items():
            file_path = os.path.join(app_dir, filename)
            with open(file_path, 'w', encoding='utf-8') as f:
                f.write(content)
        
        # 创建migrations目录
        migrations_dir = os.path.join(app_dir, 'migrations')
        os.makedirs(migrations_dir, exist_ok=True)
        with open(os.path.join(migrations_dir, '__init__.py'), 'w', encoding='utf-8') as f:
            pass
        
        # 如果是通用模块，创建额外的目录和文件
        if app_name == 'common':
            # 创建models.py，添加所有基础模型类
            with open(os.path.join(app_dir, 'models.py'), 'w', encoding='utf-8') as f:
                f.write('''import uuid

from django.db import models
from model_utils.models import TimeStampedModel, SoftDeletableModel, UUIDModel
from model_utils.fields import AutoCreatedField, AutoLastModifiedField


# 使用django-model-utils重构的通用模型继承
class BaseModel(TimeStampedModel, SoftDeletableModel):
    """
    通用基础模型，集成django-model-utils功能
    
    功能特性：
    - TimeStampedModel: 自动管理created和modified字段
    - SoftDeletableModel: 软删除功能，使用is_removed字段
    """
    
    class Meta:
        abstract = True

    # @property
    # def create_time(self):
    #     """兼容性属性，映射到created"""
    #     return self.created

    # @property
    # def update_time(self):
    #     """兼容性属性，映射到modified"""
    #     return self.modified

    # @property
    # def delete_time(self):
    #     """兼容性属性，软删除时间（django-model-utils不直接支持，返回None）"""
    #     return None

    # @property
    # def is_delete(self):
    #     """兼容性属性，映射到is_removed"""
    #     return self.is_removed

    # @is_delete.setter
    # def is_delete(self, value):
    #     """兼容性属性，映射到is_removed"""
    #     self.is_removed = value


# 主键继承模型
class IdModel(models.Model):
    """自增ID主键模型"""
    id = models.AutoField(primary_key=True)

    class Meta:
        abstract = True


class BigIdModel(models.Model):
    """大整数ID主键模型"""
    id = models.BigAutoField(primary_key=True)

    class Meta:
        abstract = True


class UUIdModel(UUIDModel):
    """
    UUID主键模型，基于django-model-utils的UUIDModel
    """
    class Meta:
        abstract = True


# 通用和主键继承的组合（使用django-model-utils）
class IdBaseModel(IdModel, BaseModel):
    """自增ID + 通用功能（时间戳 + 软删除）"""
    class Meta:
        abstract = True


class BigIdBaseModel(BigIdModel, BaseModel):
    """大整数ID + 通用功能（时间戳 + 软删除）"""
    class Meta:
        abstract = True


class UUIdBaseModel(UUIdModel, BaseModel):
    """UUID + 通用功能（时间戳 + 软删除）"""
    class Meta:
        abstract = True


# 为了更好的向后兼容，保留原始实现作为备用（已废弃但保持兼容）
class LegacyBaseModel(models.Model):
    """
    原始的通用模型实现（已废弃，建议使用BaseModel）
    保留用于向后兼容
    """
    create_time = models.DateTimeField(auto_now_add=True, verbose_name="创建时间")
    update_time = models.DateTimeField(auto_now=True, verbose_name="更新时间")
    delete_time = models.DateTimeField(null=True, blank=True, verbose_name="删除时间")
    is_delete = models.BooleanField(default=False, verbose_name="是否删除")

    class Meta:
        abstract = True


class LegacyUUIdBaseModel(LegacyBaseModel):
    """原始的UUID基础模型（已废弃）"""
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

    class Meta:
        abstract = True
''')

            # 更新admin.py，添加验证码管理
            with open(os.path.join(app_dir, 'admin.py'), 'w', encoding='utf-8') as f:
                f.write('''from django.contrib import admin
from captcha.models import CaptchaStore


@admin.register(CaptchaStore)
class CaptchaStoreAdmin(admin.ModelAdmin):
    list_display = ['hashkey', 'challenge', 'response', 'expiration', 'is_expired']
    list_filter = ['expiration']
    search_fields = ['hashkey', 'challenge', 'response']
    readonly_fields = ['hashkey', 'challenge', 'response', 'expiration', 'is_expired']
    date_hierarchy = 'expiration'
    ordering = ['-expiration']
    
    def is_expired(self, obj):
        """检查验证码是否已过期"""
        if obj.expiration is None:
            return None
        from django.utils import timezone
        return obj.expiration < timezone.now()
    is_expired.boolean = True
    is_expired.short_description = '是否过期'
    
    def has_add_permission(self, request):
        """禁用添加权限，验证码应该由系统自动生成"""
        return False
    
    def has_change_permission(self, request, obj=None):
        """禁用修改权限，验证码不应该被手动修改"""
        return False
    
    class Meta:
        verbose_name = "验证码"
        verbose_name_plural = "验证码管理"
''')

            # 更新views.py，添加CommonMixinViewSet
            with open(os.path.join(app_dir, 'views.py'), 'w', encoding='utf-8') as f:
                f.write('''from django.shortcuts import render
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import filters
from rest_framework.exceptions import NotFound
from rest_framework.viewsets import GenericViewSet

from apps.common.utils.pagination import PageNumberPaginationUtil
from apps.common.utils.response import Response as Re


# Create your views here.
class CommonMixinViewSet(GenericViewSet):
    filter_backends = [DjangoFilterBackend, filters.OrderingFilter]
    pagination_class = PageNumberPaginationUtil
    ordering = ['create_time']

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        page = self.paginate_queryset(queryset)
        if request.query_params.get('page') and page is not None:
            serializer = self.get_serializer(page, many=True)
            paginated_data = {
                'count': self.paginator.page.paginator.count,
                'next': self.paginator.get_next_link(),
                'previous': self.paginator.get_previous_link(),
                'current': self.paginator.page.number,
                'max_page': self.paginator.page.paginator.num_pages,
                'results': serializer.data
            }
            return Re.success(data=paginated_data)
        serializer = self.get_serializer(queryset, many=True)
        return Re.success(data=serializer.data)

    def retrieve(self, request, *args, **kwargs):
        try:
            instance = self.get_object()
            serializer = self.get_serializer(instance)
            return Re.success(data=serializer.data)
        except NotFound:
            return Re.not_found()

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        if serializer.is_valid():
            # 将对象保存到数据库中
            self.perform_create(serializer)  # 这里会触发 perform_create 钩子
            instance = serializer.instance  # 获取已创建的实例
            # instance = serializer.save()
            # 用序列化对象返回响应
            return Re.success(data=self.get_serializer(instance).data)
        return Re.bad_request(message="数据验证失败", data=serializer.errors)

    def update(self, request, *args, **kwargs):
        try:
            # Get the object to update
            instance = self.get_object()
        except NotFound:
            return Re.not_found()

        # 使用序列化器验证和更新对象
        serializer = self.get_serializer(instance, data=request.data, partial=True)
        if serializer.is_valid():
            # instance = serializer.save()
            self.perform_update(serializer)  # 这里会触发 perform_update 钩子
            instance = serializer.instance
            # 用更新的对象返回响应
            return Re.success(data=self.get_serializer(instance).data)
        return Re.bad_request(message="数据验证失败", data=serializer.errors)

    def destroy(self, request, *args, **kwargs):
        try:
            instance = self.get_object()
            instance.is_removed = True  # 假删除
            instance.save()
            return Re.success(data=[])
        except NotFound:
            return Re.not_found()

    # 添加这两个关键方法
    def perform_create(self, serializer):
        """提供给子类重写的钩子"""
        serializer.save()

    def perform_update(self, serializer):
        """提供给子类重写的钩子"""
        serializer.save()


METHOD_ACTION = {'get': 'list', "post": "create"}
METHOD_ACTION_SINGLE = {'get': 'retrieve', "put": "update", "delete": "destroy"}
''')

            # 创建utils目录和基本工具文件
            utils_dir = os.path.join(app_dir, 'utils')
            os.makedirs(utils_dir, exist_ok=True)
            with open(os.path.join(utils_dir, '__init__.py'), 'w', encoding='utf-8') as f:
                pass
            
            # 创建response.py
            with open(os.path.join(utils_dir, 'response.py'), 'w', encoding='utf-8') as f:
                f.write('''from rest_framework.response import Response as DRFResponse
from rest_framework import status


class Response:
    """
    统一的响应格式
    """
    
    @staticmethod
    def success(data=None, message="操作成功", status_code=status.HTTP_200_OK):
        """成功响应"""
        return DRFResponse({
            "code": 200,
            "message": message,
            "data": data,
            "success": True
        }, status=status_code)
    
    @staticmethod
    def error(message="操作失败", code=400, data=None, status_code=status.HTTP_400_BAD_REQUEST):
        """错误响应"""
        return DRFResponse({
            "code": code,
            "message": message,
            "data": data,
            "success": False
        }, status=status_code)
    
    @staticmethod
    def unauthorized(message="认证失败", data=None):
        """未认证响应"""
        return Response.error(message=message, code=401, data=data, status_code=status.HTTP_401_UNAUTHORIZED)
    
    @staticmethod
    def forbidden(message="没有权限", data=None):
        """禁止访问响应"""
        return Response.error(message=message, code=403, data=data, status_code=status.HTTP_403_FORBIDDEN)
    
    @staticmethod
    def not_found(message="资源不存在", data=None):
        """资源不存在响应"""
        return Response.error(message=message, code=404, data=data, status_code=status.HTTP_404_NOT_FOUND)

    @staticmethod
    def bad_request(message="请求参数错误", data=None):
        """请求错误响应"""
        return Response.error(message=message, code=400, data=data, status_code=status.HTTP_400_BAD_REQUEST)
''')
            
            # 创建account.py
            with open(os.path.join(utils_dir, 'account.py'), 'w', encoding='utf-8') as f:
                f.write('''from captcha.models import CaptchaStore

from django.contrib.auth.backends import ModelBackend
from django.contrib.auth.models import User
from django.db.models import Q


def code_check(captcha_key, captcha_value):
    """
    验证码校验
    """
    if not captcha_key or not captcha_value:
        return {"status": False, "msg": "验证码不能为空"}
    
    try:
        # 获取验证码
        captcha = CaptchaStore.objects.get(hashkey=captcha_key)
        if captcha.response.lower() != captcha_value.lower():
            return {"status": False, "msg": "验证码错误"}
        
        # 使用后清除
        captcha.delete()
        return {"status": True, "msg": "验证通过"}
    except CaptchaStore.DoesNotExist:
        return {"status": False, "msg": "验证码已过期"}
    except Exception as e:
        return {"status": False, "msg": f"验证失败: {str(e)}"}


class CustomBackend(ModelBackend):
    """
    自定义用户认证后端
    
    允许使用用户名或邮箱登录
    """
    
    def authenticate(self, request, username=None, password=None, **kwargs):
        try:
            # 使用用户名或邮箱查询用户
            user = User.objects.get(Q(username=username) | Q(email=username))
            
            # 检查密码
            if user.check_password(password):
                return user
        except User.DoesNotExist:
            return None
        except Exception:
            return None
        
        return None
''')
            
            # 创建pagination.py
            with open(os.path.join(utils_dir, 'pagination.py'), 'w', encoding='utf-8') as f:
                f.write('''from rest_framework.pagination import PageNumberPagination
from rest_framework.response import Response


class PageNumberPaginationUtil(PageNumberPagination):
    """
    自定义分页器
    """
    # 每页的默认显示数据量
    page_size = 10

    # URL参数中设置每页展示数量的名称
    page_size_query_param = 'page_size'

    # URL参数中设置页码的名称
    page_query_param = 'page'

    # 每页的最大数据量
    max_page_size = 100

    def get_paginated_response(self, data):
        """
        重写分页响应方法

        Args:
            data: 分页数据

        Returns:
            Response: 分页响应
        """
        return Response({
            'count': self.page.paginator.count,
            'next': self.get_next_link(),
            'previous': self.get_previous_link(),
            'current': self.page.number,
            'max_page': self.page.paginator.num_pages,
            'results': data
        })
''')
            
            # 创建middleware目录和基本中间件
            middleware_dir = os.path.join(app_dir, 'middleware')
            os.makedirs(middleware_dir, exist_ok=True)
            with open(os.path.join(middleware_dir, '__init__.py'), 'w', encoding='utf-8') as f:
                pass
                
            # 创建NetworkMiddleware.py
            with open(os.path.join(middleware_dir, 'NetworkMiddleware.py'), 'w', encoding='utf-8') as f:
                f.write('''class NetworkRequestMiddleware:
    """
    网络请求中间件
    
    用于记录请求信息
    """
    
    def __init__(self, get_response):
        self.get_response = get_response
    
    def __call__(self, request):
        # 获取请求IP
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        
        # 将IP信息添加到请求对象中
        request.client_ip = ip
        
        # 记录请求信息
        # 此处可以添加日志记录等功能
        
        response = self.get_response(request)
        return response
''')
            
            # 创建management目录和命令
            management_dir = os.path.join(app_dir, 'management')
            commands_dir = os.path.join(management_dir, 'commands')
            os.makedirs(commands_dir, exist_ok=True)
            
            with open(os.path.join(management_dir, '__init__.py'), 'w', encoding='utf-8') as f:
                pass
                
            with open(os.path.join(commands_dir, '__init__.py'), 'w', encoding='utf-8') as f:
                pass
                
            # 创建自定义命令server.py
            with open(os.path.join(commands_dir, 'server.py'), 'w', encoding='utf-8') as f:
                f.write('''"""
Django自定义管理命令：urunserver
使用uvicorn启动Django ASGI应用
"""

import os
import sys
import uvicorn
from pathlib import Path
from django.core.management.base import BaseCommand, CommandError
from django.conf import settings


class Command(BaseCommand):
    help = '使用uvicorn启动Django ASGI服务器'

    def add_arguments(self, parser):
        """添加命令行参数"""
        parser.add_argument(
            '--host',
            default='127.0.0.1',
            help='服务器绑定地址（默认: 127.0.0.1）'
        )
        
        parser.add_argument(
            '--port',
            type=int,
            default=8005,
            help='服务器端口（默认: 8005）'
        )
        
        parser.add_argument(
            '--reload',
            action='store_true',
            default=True,
            help='启用自动重载（默认: 启用）'
        )
        
        parser.add_argument(
            '--no-reload',
            action='store_false',
            dest='reload',
            help='禁用自动重载'
        )
        
        parser.add_argument(
            '--workers',
            type=int,
            default=1,
            help='工作进程数（默认: 1）'
        )
        
        parser.add_argument(
            '--log-level',
            choices=['critical', 'error', 'warning', 'info', 'debug'],
            default='info',
            help='日志级别（默认: info）'
        )
        
        parser.add_argument(
            '--no-access-log',
            action='store_false',
            dest='access_log',
            default=True,
            help='禁用访问日志'
        )

    def handle(self, *args, **options):
        """处理命令执行"""
        
        # 获取项目根目录
        BASE_DIR = Path(settings.BASE_DIR)
        
        # 获取ASGI应用模块路径
        asgi_module = f"{settings.ROOT_URLCONF.split('.')[0]}.asgi:application"
        
        # 服务器配置
        config = {
            "app": asgi_module,
            "host": options['host'],
            "port": options['port'],
            "reload": options['reload'],
            "workers": options['workers'],
            "access_log": options['access_log'],
            "log_level": options['log_level'],
        }
        
        # 如果是单进程且启用重载，添加重载目录
        if options['workers'] == 1 and options['reload']:
            config["reload_dirs"] = [str(BASE_DIR)]
        
        # 显示启动信息
        self.stdout.write(
            self.style.SUCCESS("🚀 正在启动Django ASGI服务器...")
        )
        self.stdout.write(f"📍 服务地址: http://{options['host']}:{options['port']}")
        self.stdout.write(f"👥 工作进程数: {options['workers']}")
        self.stdout.write(f"📊 日志级别: {options['log_level']}")
        self.stdout.write(f"🔄 自动重载: {'启用' if options['reload'] else '禁用'}")
        self.stdout.write(f"📝 访问日志: {'启用' if options['access_log'] else '禁用'}")
        self.stdout.write("🛑 按 Ctrl+C 停止服务器")
        self.stdout.write("-" * 50)
        
        try:
            uvicorn.run(**config)
        except KeyboardInterrupt:
            self.stdout.write(
                self.style.SUCCESS("✅ 服务器已停止")
            )
        except Exception as e:
            raise CommandError(f"❌ 启动失败: {e}")
''')
        
        # 对于accounts模块，创建基本的认证视图和URL
        elif app_name == 'accounts':
            with open(os.path.join(app_dir, 'views.py'), 'w', encoding='utf-8') as f:
                f.write('''from captcha.helpers import captcha_image_url
from captcha.models import CaptchaStore
from rest_framework.request import Request
from rest_framework.views import APIView
from rest_framework_simplejwt.exceptions import TokenError, InvalidToken
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView, TokenVerifyView
from rest_framework_simplejwt.tokens import UntypedToken
from rest_framework.exceptions import AuthenticationFailed
from django.contrib.auth.models import User
from rest_framework_simplejwt.authentication import JWTAuthentication

from apps.common.utils.account import code_check
from apps.common.utils.response import Response


class GetCaptcha(APIView):
    authentication_classes = []
    permission_classes = []

    def get(self, request):
        """
        获取验证码
        """
        # 生成新的验证码
        key = CaptchaStore.generate_key()
        image_url = captcha_image_url(key)
        # 获取验证码的值
        # captcha_text = CaptchaStore.objects.get(hashkey=key).challenge
        return Response.success(data={"captcha_key": key, "image_url": image_url})


class LoginTokenObtainPairView(TokenObtainPairView):
    """ 登录视图 """

    def post(self, request: Request, *args, **kwargs):
        code_check_result = code_check(request.data.get("captcha_key"), str(request.data.get("captcha_value")))
        if not code_check_result["status"]:
            return Response.error(message=code_check_result["msg"])
            # 登入
        serializer = self.get_serializer(data=request.data)
        try:
            serializer.is_valid(raise_exception=True)
        except TokenError as e:
            print(e.args[0])
            return InvalidToken(e.args[0])
        except AuthenticationFailed as e:
            print(e.args[0])
            return Response.unauthorized(message=e.detail)
        result = serializer.validated_data
        result["username"] = serializer.user.username
        return Response.success(result)


class CustomTokenRefreshView(TokenRefreshView):
    """
    刷新Token视图
    使用统一的响应结构
    """
    
    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        
        try:
            serializer.is_valid(raise_exception=True)
        except TokenError as e:
            return Response.unauthorized(message="Token无效或已过期")
        except Exception as e:
            return Response.error(message="Token刷新失败")
            
        result = serializer.validated_data
        return Response.success(data=result, message="Token刷新成功")


class CustomTokenVerifyView(TokenVerifyView):
    """
    验证Token视图
    如果是access token验证成功，返回用户数据
    如果是refresh token验证成功，不返回用户数据
    """
    
    def post(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        
        try:
            serializer.is_valid(raise_exception=True)
        except TokenError as e:
            return Response.unauthorized(message="Token无效或已过期")
        except Exception as e:
            return Response.error(message="Token验证失败")
        
        # Token验证成功，现在判断token类型
        token_value = request.data.get('token')
        
        try:
            # 尝试解析token
            untyped_token = UntypedToken(token_value)
            token_type = untyped_token.get('token_type')
            
            response_data = {
                "token_type": token_type,
                "is_valid": True
            }
            
            # 如果是access token，返回用户数据
            if token_type == 'access':
                try:
                    # 使用JWT认证获取用户
                    jwt_auth = JWTAuthentication()
                    validated_token = jwt_auth.get_validated_token(token_value)
                    user = jwt_auth.get_user(validated_token)
                    
                    # 返回基本用户信息
                    user_data = {
                        "id": user.id,
                        "username": user.username,
                        "email": user.email,
                        "first_name": user.first_name,
                        "last_name": user.last_name,
                        "is_active": user.is_active,
                        "is_staff": user.is_staff,
                        "is_superuser": user.is_superuser,
                        "date_joined": user.date_joined.isoformat(),
                        "last_login": user.last_login.isoformat() if user.last_login else None
                    }
                    response_data["user"] = user_data
                    
                except Exception as e:
                    # 如果获取用户信息失败，只返回基本验证信息
                    pass
            
            return Response.success(data=response_data, message="Token验证成功")
            
        except Exception as e:
            # 如果无法解析token类型，返回基本验证成功信息
            return Response.success(data={"is_valid": True}, message="Token验证成功")
''')
            
            # 更新accounts的URLs
            with open(os.path.join(app_dir, 'urls.py'), 'w', encoding='utf-8') as f:
                f.write('''from rest_framework_simplejwt.views import TokenRefreshView, TokenVerifyView
from django.urls import path

from . import views

drf_patterns = [
    path('token/', views.LoginTokenObtainPairView.as_view(), name='token_obtain_pair'),
    # 刷新Token有效期的接口
    path('token/refresh/', views.CustomTokenRefreshView.as_view(), name='token_refresh'),
    # 验证Token的有效性
    path('token/verify/', views.CustomTokenVerifyView.as_view(), name='token_verify'),

    # 验证码获取
    path('captcha/', views.GetCaptcha.as_view()),

]

urlpatterns = drf_patterns
''')
        
        print(f"应用 {app_name} 创建成功")

    def update_settings(self):
        """更新settings.py文件"""
        print("正在更新settings.py...")
        
        settings_path = os.path.join(self.base_dir, self.project_name, 'settings.py')
        
        # 备份原始设置文件
        backup_file = f"{settings_path}.bak"
        if not os.path.exists(backup_file):
            shutil.copy2(settings_path, backup_file)
            print(f"已创建设置文件备份: {backup_file}")
        
        try:
            with open(settings_path, 'r', encoding='utf-8') as f:
                settings_content = f.read()
            
            # 导入必要的模块
            if 'import os' not in settings_content:
                settings_content = 'import os\nimport datetime\n' + settings_content
            elif 'import datetime' not in settings_content:
                settings_content = settings_content.replace('import os', 'import os\nimport datetime')
            
            # 更新ALLOWED_HOSTS
            settings_content = settings_content.replace('ALLOWED_HOSTS = []', 'ALLOWED_HOSTS = ["*"]')
            
            # 更新语言和时区设置
            settings_content = settings_content.replace("LANGUAGE_CODE = 'en-us'", "LANGUAGE_CODE = 'zh-hans'")
            settings_content = settings_content.replace("TIME_ZONE = 'UTC'", "TIME_ZONE = 'Asia/Shanghai'")
            
            # 添加USE_TZ和USE_I18N设置
            if 'USE_TZ = True' in settings_content:
                settings_content = settings_content.replace('USE_TZ = True', 'USE_TZ = False')
            
            # 添加跨域设置
            if 'X_FRAME_OPTIONS = "DENY"' in settings_content:
                settings_content = settings_content.replace('X_FRAME_OPTIONS = "DENY"', 'X_FRAME_OPTIONS = "ALLOWALL"')
            
            # 添加INSTALLED_APPS
            # 修改前：
            simpleui_app = ["    'simpleui',  # 后台管理"]
            django_apps = [
                "    'django.contrib.admin',",
                "    'django.contrib.auth',",
                "    'django.contrib.contenttypes',",
                "    'django.contrib.sessions',",
                "    'django.contrib.messages',",
                "    'django.contrib.staticfiles',",
            ]
            third_party_apps = [
                "    'drf_spectacular',  # OpenAPI 接口",
                "    'django_filters',  # 过滤器",
                "    'rest_framework',  # 序列化",
                "    'rest_framework_simplejwt',  # 认证",
                "    'rest_framework_simplejwt.token_blacklist',  # 黑名单",
                "    'corsheaders',  # 跨域",
                "    'mptt',  # 树形结构",
                "    'captcha',  # 图片验证码",
            ]
            local_apps = [
                "    # 应用模块",
                "    'apps.accounts',  # 认证",
                "    'apps.common',  # 公共",
            ]
            
            # 修改为：
            # 查找INSTALLED_APPS并添加新应用
            if 'INSTALLED_APPS = [' in settings_content:
                # 找到INSTALLED_APPS列表的开始
                start_index = settings_content.find('INSTALLED_APPS = [')
                # 找到INSTALLED_APPS列表结束的]
                end_index = settings_content.find(']', start_index)
                
                # 获取原始的Django应用
                original_apps_str = settings_content[start_index + len('INSTALLED_APPS = ['):end_index].strip()
                original_apps = [app.strip() for app in original_apps_str.split('\n') if app.strip()]
                
                # 构建新的INSTALLED_APPS，确保simpleui在最前面
                new_installed_apps = 'INSTALLED_APPS = [\n'
                
                # 添加simpleui
                for app in simpleui_app:
                    if not any(app.split('#')[0].strip() in original_app for original_app in original_apps):
                        new_installed_apps += f"{app}\n"
                
                # 添加Django内置应用
                for app in django_apps:
                    if not any(app.split('#')[0].strip() in original_app for original_app in original_apps):
                        new_installed_apps += f"{app}\n"
                    else:
                        # 如果已存在，保留原有的配置
                        for original_app in original_apps:
                            if app.split('#')[0].strip() in original_app:
                                new_installed_apps += f"{original_app}\n"
                                break
                
                # 添加第三方应用
                for app in third_party_apps:
                    if not any(app.split('#')[0].strip() in original_app for original_app in original_apps):
                        new_installed_apps += f"{app}\n"
                
                # 添加本地应用
                for app in local_apps:
                    if not any('apps.' in app and app.split('#')[0].strip() in original_app for original_app in original_apps):
                        new_installed_apps += f"{app}\n"
                
                new_installed_apps += ']'
                
                # 替换原有的INSTALLED_APPS
                settings_content = settings_content[:start_index] + new_installed_apps + settings_content[end_index+1:]
            
            # 添加MIDDLEWARE
            if 'MIDDLEWARE = [' in settings_content and 'apps.common.middleware.NetworkMiddleware.NetworkRequestMiddleware' not in settings_content:
                settings_content = settings_content.replace(
                    "'django.middleware.clickjacking.XFrameOptionsMiddleware',",
                    "'django.middleware.clickjacking.XFrameOptionsMiddleware',\n    'apps.common.middleware.NetworkMiddleware.NetworkRequestMiddleware',"
                )
            
            # 修复TEMPLATES配置
            # 查找TEMPLATES配置
            if "'DIRS': []," in settings_content:
                settings_content = settings_content.replace(
                    "'DIRS': [],",
                    "'DIRS': [os.path.join(BASE_DIR, 'templates')],"
                )

# 修复重复的STATIC_URL
            # 添加静态文件和媒体文件配置
            media_config = """
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/5.2/howto/static-files/
STATIC_URL = 'static/'

# 收集静态文件的根目录
STATIC_ROOT = os.path.join(BASE_DIR, 'static')

# 额外的静态文件目录
# STATICFILES_DIRS = [
#     os.path.join(BASE_DIR, 'static/'),
# ]

MEDIA_URL = '/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
"""
            # 删除重复的STATIC_URL定义
            # 首先检查是否存在原始的STATIC_URL
            static_url_index = settings_content.find('STATIC_URL =')
            if static_url_index != -1:
                # 找到第一个定义后的换行符
                end_line = settings_content.find('\n', static_url_index)
                # 如果找到了结束位置，那么从静态URL定义到下一行的开始都应该被删除
                if end_line != -1:
                    # 检查后面是否有另一个STATIC_URL定义
                    next_static_url = settings_content.find('STATIC_URL =', end_line)
                    if next_static_url != -1:
                        # 找到重复定义的结束位置
                        next_end_line = settings_content.find('\n', next_static_url)
                        if next_end_line != -1:
                            # 删除第二个STATIC_URL定义
                            settings_content = settings_content[:next_static_url] + settings_content[next_end_line+1:]
            
            # 确保不会重复添加
            if 'MEDIA_ROOT = ' not in settings_content:
                # 查找和替换整个静态文件配置部分
                static_pattern = "# Static files (CSS, JavaScript, Images)"
                static_index = settings_content.find(static_pattern)
                if static_index != -1:
                    # 找到这一部分的结束
                    static_end = settings_content.find('\n\n', static_index)
                    if static_end != -1:
                        settings_content = settings_content[:static_index] + media_config + settings_content[static_end+2:]
                    else:
                        settings_content += media_config
                else:
                    settings_content += media_config
            
            # 添加CORS配置
            cors_config = """
# CORS跨域
CORS_ALLOW_ALL_ORIGINS = True
"""
            if 'CORS_ALLOW_ALL_ORIGINS' not in settings_content:
                settings_content += cors_config
            
            # 添加REST_FRAMEWORK配置
            rest_framework_config = """
# 配置JWT认证
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        # 默认认证方式
        'rest_framework_simplejwt.authentication.JWTAuthentication',  # JWT认证
        'rest_framework.authentication.SessionAuthentication',  # 会话认证
        'rest_framework.authentication.BasicAuthentication',  # 基本认证（用于API文档登录）
    ],
    # 默认权限控制
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',  # 默认要求认证
    ],
    # 匿名用户限流
    'DEFAULT_THROTTLE_CLASSES': [
        'rest_framework.throttling.AnonRateThrottle',
    ],
    'DEFAULT_THROTTLE_RATES': {
        'anon': '50/hour',  # 匿名用户每小时50次
        'user': '1000/hour'  # 认证用户每小时1000次
    },
    # 配置OpenAPI
    'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
}

SPECTACULAR_SETTINGS = {
    'TITLE': '平台的API',
    'DESCRIPTION': '这是项目的API文档',
    'VERSION': '1.0.0',
    'SERVE_INCLUDE_SCHEMA': False,  # 是否包含架构
    'SCHEMA_PATH_PREFIX': None,  # 架构路径前缀
    "SWAGGER_UI_SETTINGS": {
        "deepLinking": True,  # 是否深链接
        "persistAuthorization": True,  # 是否持久化授权
        "displayOperationId": True,  # 是否显示操作ID
    },
    'COMPONENT_SPLIT_REQUEST': True,
    'SECURITY': [
        {
            'basicAuth': [],  # 基本认证
        },
        {
            'bearerAuth': [],  # JWT认证
        },
        {
            'cookieAuth': [],  # 会话认证
        }
    ],
    'COMPONENTS': {
        'securitySchemes': {
            'basicAuth': {
                'type': 'http',
                'scheme': 'basic',
                'description': '使用用户名和密码进行基本认证'
            },
            'bearerAuth': {
                'type': 'http',
                'scheme': 'bearer',
                'bearerFormat': 'JWT',
                'description': '使用JWT Token进行认证，格式：Bearer <token>'
            },
            'cookieAuth': {
                'type': 'apiKey',
                'in': 'cookie',
                'name': 'sessionid',
                'description': '使用会话Cookie进行认证'
            }
        }
    },
}

# 指定认证方式
AUTHENTICATION_BACKENDS = (
    'apps.common.utils.account.CustomBackend',
    'django.contrib.auth.backends.ModelBackend',  # default
)

# 字母验证码
CAPTCHA_IMAGE_SIZE = (120, 48)  # 设置 captcha 图片大小
CAPTCHA_LENGTH = 4  # 字符个数
CAPTCHA_TIMEOUT = 5  # 超时(minutes)

# JWT设置
SIMPLE_JWT = {
    # 时区设置
    'TIME_ZONE': 'Asia/Shanghai', 
    # 访问令牌的有效期，设置为5分钟
    'ACCESS_TOKEN_LIFETIME': datetime.timedelta(minutes=5),
    # 刷新令牌的有效期，设置为1天
    'REFRESH_TOKEN_LIFETIME': datetime.timedelta(days=1),
    # 是否在刷新访问令牌时旋转刷新令牌
    'ROTATE_REFRESH_TOKENS': False,
    # 在刷新令牌旋转后，是否将旧的刷新令牌加入黑名单
    'BLACKLIST_AFTER_ROTATION': True,
    # 是否在用户登录时更新他们的最后登录时间
    'UPDATE_LAST_LOGIN': True,
    # 签名算法
    'ALGORITHM': 'HS256',
    # 用于签名JWT的密钥
    'SIGNING_KEY': SECRET_KEY,
    # 用于验证JWT的公钥
    'VERIFYING_KEY': None,
    # 指定JWT的audience（受众）声明
    'AUDIENCE': None,
    # 指定JWT的issuer（发行者）声明
    'ISSUER': None,
    # 认证头部的类型
    'AUTH_HEADER_TYPES': ('Bearer',),
    # 认证头部的名称
    'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
    # 用户模型中的字段，用于唯一标识用户
    'USER_ID_FIELD': 'id',
    # JWT中的声明，用于存储用户ID
    'USER_ID_CLAIM': 'user_id',
    # 用于确定用户是否通过认证的规则
    'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule',
    # 允许的认证令牌类
    'AUTH_TOKEN_CLASSES': (
        'rest_framework_simplejwt.tokens.AccessToken',
    ),
    # JWT中的声明，用于标识令牌类型
    'TOKEN_TYPE_CLAIM': 'token_type',
    # 自定义的用户类，用于表示JWT中的用户信息
    'TOKEN_USER_CLASS': 'rest_framework_simplejwt.models.TokenUser',
    # JWT中的声明，用于存储JWT的唯一标识符
    'JTI_CLAIM': 'jti',
}
"""
            if 'REST_FRAMEWORK' not in settings_content:
                settings_content += rest_framework_config
            
            # 写入更新后的settings.py文件
            with open(settings_path, 'w', encoding='utf-8') as f:
                f.write(settings_content)
            
            print("settings.py文件更新成功")
            
        except Exception as e:
            print(f"更新settings.py文件时出错: {e}")
            sys.exit(1)

    def update_urls(self):
        """更新主urls.py文件"""
        print("正在更新urls.py...")
        
        urls_path = os.path.join(self.base_dir, self.project_name, 'urls.py')
        
        # 备份原始urls文件
        backup_file = f"{urls_path}.bak"
        if not os.path.exists(backup_file):
            shutil.copy2(urls_path, backup_file)
            print(f"已创建urls文件备份: {backup_file}")
        
        try:
            # 读取现有urls.py文件
            with open(urls_path, 'r', encoding='utf-8') as f:
                urls_content = f.read()
            
            # 检查是否已经包含我们要添加的路由
            has_accounts = 'path(\'accounts/\'' in urls_content
            has_common = 'path(\'common/\'' in urls_content
            has_spectacular = 'SpectacularAPIView' in urls_content
            has_captcha = 'path(\'captcha/\'' in urls_content
            has_static_media = 're_path(r\'media/' in urls_content
            
            # 如果已经包含大部分特征，可能已经是我们需要的格式
            if has_accounts and has_common and has_spectacular and has_captcha and has_static_media:
                print("urls.py已包含必要的配置，跳过更新")
                return
            
            # 创建新的urls.py内容
            urls_content = '''"""
URL configuration for {project_name} project.
"""
from django.contrib import admin
from django.urls import path, include, re_path
from django.views.static import serve
from django.conf import settings

from rest_framework import permissions
from drf_spectacular.views import SpectacularAPIView, SpectacularSwaggerView, SpectacularRedocView

path_list = [
    path('accounts/', include('apps.accounts.urls')),
    path('common/', include('apps.common.urls')),
]


urlpatterns = [
    path('doc/schema/', SpectacularAPIView.as_view(), name='schema'),  # schema的配置文件的路由
    path('doc/swagger/', SpectacularSwaggerView.as_view(url_name='schema'), name='swagger-ui'),  # swagger-ui的路由
    path('doc/redoc/', SpectacularRedocView.as_view(url_name='schema'), name='redoc'),  # redoc的路由

    path('admin/', admin.site.urls),

    # 验证码
    path('captcha/', include('captcha.urls')),

    # 应用模块
    # 全局的前缀
    path('', include(path_list)),

    # 配置静态资源路由
    re_path(r'media/(?P<path>.*)$', serve, {{'document_root': settings.MEDIA_ROOT}}),

    # 设置static路由
    re_path(r'static/(?P<path>.*)$', serve, {{'document_root': settings.STATIC_ROOT}}),
]
'''.format(project_name=self.project_name)
            
            # 写入新的urls.py文件
            with open(urls_path, 'w', encoding='utf-8') as f:
                f.write(urls_content)
            
            print("urls.py文件更新成功")
            
        except Exception as e:
            print(f"更新urls.py文件时出错: {e}")
            sys.exit(1)


def main():
    """主函数"""
    parser = argparse.ArgumentParser(description="Django项目结构优化工具")
    parser.add_argument("project_name", help="项目名称")
    parser.add_argument("--path", help="项目路径，默认为当前目录", default=None)
    
    args = parser.parse_args()
    
    optimizer = DjangoProjectOptimizer(args.project_name, args.path)
    optimizer.run()


if __name__ == "__main__":
    main()